package jwebtester.security.auth;

import infrastructure.Scopes;

import java.util.ArrayList;
import java.util.List;

import jwebtester.business.services.SessionMapService;
import jwebtester.business.utils.SessionMapKeys;
import jwebtester.dal.provider.SecurityDataProvider;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.provisioning.UserDetailsManager;
import org.springframework.stereotype.Service;

import domain.entities.Authentication;
import domain.entities.Permission;

@Service
@Scope(Scopes.Singleton)
public class UserDetailsService implements UserDetailsManager {

	private static final Logger LOG = LoggerFactory.getLogger(UserDetailsService.class);

	@Autowired
	private transient SecurityDataProvider dataProvider;

	@Autowired
	private transient SessionMapService sessionMapService;

	@Override
	public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {

		Authentication auth = null;
		User result = null;
		try {
			auth = dataProvider.getAuthentication(username);

			if (auth == null) {
				throw new UsernameNotFoundException(String.format("User name not found: [%s]",
						username));
			} else {
				final int userID = auth.getUserID();
				final String hashedPassword = auth.getPassword();
				final domain.entities.User dbUser = dataProvider.getUser(userID);

				sessionMapService.put(SessionMapKeys.CURRENT_USER, dbUser);
				sessionMapService.put(SessionMapKeys.CURRENT_AUTH, auth);

				result = new User(auth.getLogin(), hashedPassword, !dbUser.getIsDisabled(), true,
						true, true, getGrantedAuthorities(dbUser));
			}
		} catch (Exception e) {
			LOG.error("Error loading authentication details from db", e);
		}

		return result;

	}

	private List<GrantedAuthority> getGrantedAuthorities(final domain.entities.User user) {
		final List<GrantedAuthority> result = new ArrayList<GrantedAuthority>();
		for (Permission pe : user.getPermissionsList()) {
			result.add(new GrantedAuthorityImpl(pe.getName())); //NOPMD
		}
		return result;
	}

	@Override
	public void createUser(final UserDetails user) {
		throw new UnsupportedOperationException(NOT_IMPLEMENTED);
	}

	@Override
	public void updateUser(final UserDetails user) {
		throw new UnsupportedOperationException(NOT_IMPLEMENTED);
	}

	@Override
	public void deleteUser(final String username) {
		throw new UnsupportedOperationException(NOT_IMPLEMENTED);
	}

	@Override
	public void changePassword(final String oldPassword, final String newPassword) {
		throw new UnsupportedOperationException(NOT_IMPLEMENTED);
	}

	@Override
	public boolean userExists(final String username) {
		throw new UnsupportedOperationException(NOT_IMPLEMENTED);
	}
	
	private static final String NOT_IMPLEMENTED = "Not yet implemented";
}
